﻿using DiscUtils;
using DiscUtils.Iso9660;
using ReaderWriter.IO;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Disk = System.IO;
namespace ReaderWriter.Providers
{
    public class IsoReaderWriter : IReaderWriter
    {
        FolderNode rootFolder;
        CDReader iso;
         Stream reader;
        public FolderNode CurrentDirectory
        {
            get { return  rootFolder; }
            set { rootFolder = value; }
        }
        string rootPath;
        int recurseLevel = 0;
        public IsoReaderWriter(string root)
        {
            rootPath = root;
            reader = System.IO.File.OpenRead(rootPath);
            iso = new CDReader(reader, true);            
        }
        ~IsoReaderWriter()
        {
            if (reader != null)
            {
                reader.Close();
            }
            reader = null;
            iso = null;
        }
        private FolderNode ReadFolderFromDirectory(DiscDirectoryInfo dr)
        {
            FolderNode folder = new FolderNode(this);
            folder.FullName = dr.FullName;
            folder.Created = dr.CreationTimeUtc;
            folder.Name = dr.Name;
            folder.Parent = dr.Parent == null ? null : ReadFolderFromDirectory(dr.Parent);
            folder.Updated = dr.LastWriteTimeUtc;
            folder.Uri = dr.FullName;
            folder.User = Environment.UserName;
            folder.StorageType = StorageType.Folder;
            return folder;
        }
        private FileNode ReadFileFromDirectory(DiscFileInfo info, FolderNode parent)
        {
            FileNode file = new FileNode(this);
            file.FullName = info.FullName;
            file.Created = info.CreationTimeUtc;
            file.Name = info.Name;
            file.Parent = parent;// info.Directory == null ? null : ReadFolderFromDirectory(info.Directory);
            file.Updated = info.LastWriteTimeUtc;
            file.Uri = info.FullName;
            file.User = Environment.UserName;
            file.StorageType = StorageType.File;
            return file;
        }
        public FolderNode Up(string uri)
        {
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(uri);
            if (dr.Parent != null)
            {
                rootFolder = ReadFolderFromDirectory(dr.Parent);
                rootFolder.Parent = null; // this means , this is root
                return rootFolder;
            }
            return null;
        }
        public FolderNode GetRoot()
        {
            DiscDirectoryInfo dr = iso.GetDirectoryInfo("\\");
            rootFolder = ReadFolderFromDirectory(dr);
            rootFolder.Parent = null; // this means , this is root
            return rootFolder;
        }
        public List<StorageNode> GetAllNodes(string uri)
        {
            recurseLevel++;
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(uri);
            var dirs = (from d in dr.GetDirectories() select ReadFolderFromDirectory(d)).ToList();
            var parent = ReadFolderFromDirectory(dr);
            var files = (from f in dr.GetFiles() select ReadFileFromDirectory(f, parent)).ToList();
            List<StorageNode> nodes = new List<StorageNode>(dirs);
            nodes.AddRange(files);
            return nodes;
        }
        public List<FolderNode> GetFolders(string uri, bool recurse, int recurseLevel=0)
        {
            recurseLevel++;
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(uri);
            var dirs = (from d in dr.GetDirectories() select ReadFolderFromDirectory(d)).ToList();
            if (recurse == true && recurseLevel < 5)
            {
                dirs.ForEach(d =>
                {
                    var folders = GetFolders(d.FullName, recurse, recurseLevel);
                    foreach (var f in folders)
                    {
                        d.Children.Add(f);
                    }
                });
            }
            return dirs;
        }
        public List<FolderNode> GetFolders(FolderNode root)
        {
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(root.FullName);
            var dirs = (from d in dr.GetDirectories() select ReadFolderFromDirectory(d));
            return dirs.ToList();
        }

        public List<FileNode> GetFiles(FolderNode parent)
        {
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(parent.FullName);
            var files = (from d in dr.GetFiles() select ReadFileFromDirectory(d, parent));
            return files.ToList();
        }

        public FolderNode GetFolder(string uri)
        {
            DiscDirectoryInfo dr = iso.GetDirectoryInfo(uri);
            return ReadFolderFromDirectory(dr);
        }

        public FileNode GetFile(string uri, bool fillWithContent = false)
        {
            DiscFileInfo info = iso.GetFileInfo(uri);
            FileNode file = ReadFileFromDirectory(info, ReadFolderFromDirectory(info.Directory));
            if (fillWithContent)
            {
                file.Data = File.ReadAllBytes(uri);
            }
            return file;
        }

        public FileNode CreateFile(FolderNode parent, FileNode file, bool overriteProperties = true)
        {
            string fullName = parent.FullName + "\\" + file.Name;
            if (!File.Exists(fullName))
                File.Create(fullName).Close();
            return GetFile(fullName);
        }

        public FolderNode CreateFolder(FolderNode parent, FolderNode child, bool overriteProperties = true)
        {
            string fullName = parent.FullName + "\\" + child.Name;
            if (! Directory.Exists(fullName))
                 Directory.CreateDirectory(fullName);
            return GetFolder(fullName);
        }

        public FileNode WriteFile(FileNode file)
        {
            File.WriteAllBytes(file.FullName, file.Data);
            return file;
        }

        public FileNode ReadFile(FileNode file)
        {
            file.Data = File.ReadAllBytes(file.FullName);
            return file;
        }

        public bool IsFolderExist(FolderNode folder)
        {
            return  Directory.Exists(folder.FullName);
        }

        public bool IsFileExist(FileNode file)
        {
            return File.Exists(file.FullName);
        }

        public bool DeleteFile(FileNode file)
        {
            File.Delete(file.FullName);
            return true;
        }

        public bool RemoveFolder(FolderNode folder)
        {
             Directory.Delete(folder.FullName);
            return true;
        }
        public string Execute(string uri)
        {
            return uri;
        }
    }
}
